from rest_framework import serializers
from books.models import BookInfo


class HeroSerialzier(serializers.Serializer):
    """
        英雄表序列化器
    """
    hname = serializers.CharField()
    hgender = serializers.IntegerField()
    hcomment = serializers.CharField()


class BookSerializer(serializers.Serializer):
    """
        自定义序列化器类继承rest_framework封装好的序列化器类
    """
    # 定义字段 结构形式和模型类定义类似 需要指定类型
    # id字段返回是需要参与序列化  但是保存数据时前端没有传递不需要参数反序列化的验证
    # 未指定read_only=True和write_only=True表示字段两个过程都参与
    # 通选项参数read_only=True控制字段参与序列化过程
    id = serializers.IntegerField(read_only=True)
    # 反序列化中可用通过选项参数进行字段验证
    btitle = serializers.CharField(max_length=20, min_length=5)
    bpub_date = serializers.DateField()
    bread = serializers.IntegerField(max_value=100, min_value=10, default=0)
    # 评论量在结果返回时不参与序列化返回 write_only表示该字段只参与反序列化
    # bcomment = serializers.IntegerField(write_only=True)
    # 指定默认值按照默认值的形式进行验证
    bcomment = serializers.IntegerField(default=0)

    # 定义序列化器的关联字段
    # 参考关联查询  主表关联副表 book.heroinfo_set   副表关联主表 hero.hbook
    # 返回的关联数据有三种形式
    # 1、返回关联数据的id值  PrimaryKeyRelatedField  注意：一本图书对应多个英雄，返回需要指定many=True
    # heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
    # 2、返回关联模型类中定义的__str__方法的结果
    # heroinfo_set = serializers.StringRelatedField(many=True)
    # 3、返回定义的另外一个序列化器指定的字段
    heroinfo_set = HeroSerialzier(read_only=True, many=True)

    # 方法验证
    # 单一字段方法验证  validate_字段名()
    # 图书书名不能为python
    def validate_btitle(self, attrs):
        """
            单一字段验证，验证btitle的数据
        :param attrs: 接受字段数据  图书书名
        :return:
        """
        if attrs == 'python':
            # 验证不通过，需要抛出异常，异常信息被视图中的errors获取
            raise serializers.ValidationError('图书书名不能为python')
        # 注意: 验证后必须将验证的数据进行返回
        return attrs

    # 多个字段方法验证
    # 图书的阅读量不能小于评论量
    def validate(self, attrs):
        """
        多个字段方法验证，图书的阅读量不能小于评论量
        :param attrs: 接受验证的字段数据 可以按照字典取值的形式获取字段数据
        :return:
        """
        if attrs['bread'] < attrs['bcomment']:
            # 验证不通过，需要抛出异常，异常信息被视图中的errors获取
            raise serializers.ValidationError('图书的阅读量不能小于评论量')
        # 注意: 验证后必须将验证的数据进行返回
        return attrs

    # 封装保存业务
    def create(self, validated_data):
        """
            保存图书
        :param validated_data: 接受验证成功后的数据 字典数据
        :return:
        """
        book = BookInfo.objects.create(**validated_data)
        # 将保存后的数据对象进行返回
        return book

    # 封装更新业务
    def update(self, instance, validated_data):
        """

        :param instance: 要更新的数据对象
        :param validated_data: 验证成功后的数据
        :return:
        """
        # 赋值更新，需要save
        # instance.btitle = validated_data.get('btitle')
        # instance.bpub_date = validated_data.get('bpub_date')
        # instance.bread = validated_data.get('bread')
        # instance.bcomment = validated_data.get('bcomment')
        # instance.save()
        # 模型类中的update方法
        res = BookInfo.objects.filter(id=instance.id).update(**validated_data)
        # 再查询一下数据库获取最新的更新数据
        instance = BookInfo.objects.get(id=instance.id)
        return instance
